package org.lh.ibernate.core.impl;

import org.lh.ibernate.annotation.Column;
import org.lh.ibernate.core.IResultSetHandler;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class ResultSetHandler implements IResultSetHandler {

    private Class<?> beanClass;

    public ResultSetHandler(Class<?> beanClass) {
        this.beanClass = beanClass;
    }

    public void setBeanClass(Class<?> beanClass){
        this.beanClass=beanClass;
    }

    public Class<?> getBeanClass(){
        return beanClass;
    }

    //将单个结果集转换为相应的object对象
    @Override
    public Object handle(ResultSet rs) throws SQLException {
        try {
            if (!rs.next()) {
                return null;
            }
            // 用于封装数据的bean
            Object bean = beanClass.newInstance();
            ConcurrentHashMap<String,String> map=initObjColumn(beanClass);
            ResultSetMetaData meta = rs.getMetaData();
            int columnCount = meta.getColumnCount();
            for (int i = 0; i < columnCount; i++) {
                String columnName = meta.getColumnName(i + 1);
                Object columnValue = rs.getObject(columnName);
                try {
                    //属性修改器
                    PropertyDescriptor pd = new PropertyDescriptor(map.get(columnName),
                            bean.getClass());
                    Method method = pd.getWriteMethod(); //获取所有写的方法（setter）
                    method.invoke(bean, columnValue);
                } catch (Exception e) {
                   e.printStackTrace();
                }
            }
            return bean;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            rs.close();
        }
    }


    //扫描一个类里面的属性和@Column的值
    private ConcurrentHashMap initObjColumn(Class clazz){
        ConcurrentHashMap<String,String> map=new ConcurrentHashMap<String,String>();
        Field[] fields=clazz.getDeclaredFields();
        for (Field field : fields) {
            if(field.isAnnotationPresent(Column.class)){
                Column column=field.getAnnotation(Column.class);
                map.put(column.value(),field.getName());  //存放相应的字段名--属性名
            }
        }
        return map;
    }

    //将多个结果集转换为相应的list集合
    @Override
    public List<Object> handleList(ResultSet resultSets) throws SQLException {
        try {
            if (!resultSets.next()) {
                return null;
            }
            resultSets.last();
            int totalRows=resultSets.getRow();
            resultSets.first();
           // 用于封装数据的beanlist
            ConcurrentHashMap<String,String> map=initObjColumn(beanClass);
            List<Object> beanList=new ArrayList<Object>();
            for(int index=0;index<totalRows;index++){
                ResultSetMetaData meta = resultSets.getMetaData();
                int columnCount = meta.getColumnCount();
                Object bean = beanClass.newInstance();  //使用newinstance，而不使用new的原因 ，使用newinstance的时候，类已经被加载了
                    for (int i = 0; i < columnCount; i++) {
                        String columnName = meta.getColumnName(i + 1);
                        Object columnValue = resultSets.getObject(columnName);
                        try {
                            //属性修改器
                            PropertyDescriptor pd = new PropertyDescriptor(map.get(columnName),
                                    bean.getClass());
                            Method method = pd.getWriteMethod(); //获取所有写的方法（setter）
                            method.invoke(bean, columnValue);//等价于对该bean方法执行相应的setter方法
                        } catch (Exception e) {
                            continue;
                        }
                    }
                resultSets.next();
                beanList.add( bean);
            }
            resultSets.close();
            return beanList;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
